Apollo-client中的本地数据管理方法. 和远程数据的流动方向一样, 但是在到达 server之前会被 apollo-link-state 截获,并做处理.数据仍然保持单向流动.
调用withClientState方法,并使用 resolver做对应的处理.
1 | import { withClientState } from 'apollo-link-state'; |
在 Apollo-client 上挂载 state,state link 应该在在链的末端,由此其他的 link 可以做逻辑上的处理, 但是必须要在 HttpLink之前,只有这样本地的操作才可以在到达网络之前被截获. 如果使用了持久化查询(persisted queries), 也必须要在apollo-link-persisted-queries之前.
1 | const client = new ApolloClient({ |
请求远程数据和本地数据,通过@client指令来区分.
1 | const UPDATE_NETWORK_STATUS = gql` |
在组件注入 query 或者 mutate 就可以了
1 | const WrappedComponent = graphql(UPDATE_NETWORK_STATUS, { |
如果要从其他组件访问 nework status 怎么办? 因为在访问之前,并不知道是否有UPDATA_NETWORK_STATUS存在,为了防止出现 undefined,需要提供一个默认的 state 作为初始值.
1 | const stateLink = withClientState({ |
组件查询 network也使用@client指令
1 | const GET_ARTICLES = gql` |
Defaults
1 | const defaults = { |
Resolvers
resolvers 是实现 local state 的地方. resolver的 map是对应每个 GraphQL 对象类型的resolver 函数.
apollo-link-state有四个重要的部分
- cache在上下文中,可以用来读取数据
- resolver 应该返回一个有
_typename属性的对象, 也可以用dataIdFromObject代替. 目的是 Apollo 用于数据的normalize - 如果需要执行异步操作,可以使用 promise.
- Query只针对 cache. 如果在所有的 mutate 之前执行 query,需要提供默认值
Default resolvers
不一定要为每个字段都建立特定的 resolvers,如果从 parent 对象返回的值和children 请求的字段一致,就不需要 resolvers.这就是default resovlers
1 |
|
Resolvers signature
Apollo-client 中的resolver 函数和用graph-tools构建的 server 中的 resolvers 是完全一样的.
1 | fieldName:(obj,args,context,info)=>result; |
obj: 包含 parent 字段 或者ROOT_QUERY对象args: 传递进入的参数, 例如updataNetworkStatus(isConnected:true),args对象就是{isConnected:true}context: 在所有的link 中共享的数据. 重要的的一点是Apollo cache添加在其中,所以可以用cache.writeData({}).如果想设定额外的值,可以在组件内设定,或者使用apollo-link-context.info: 有关 state 执行状态的信息. 个人不会用到
Async resolvers
如果想访问 REST 数据,可以参考apollo-link-rest.
对于 RN或者 其他的 browser API,需要在组件的生命周期方法中添加触发函数.
这一部分暂时不写
Organizing resolvers
使用鸭子类型 ,每个feature都有自己的一套方法,然后合并起来
1 | import merge from 'lodash.merge'; |
可以设定默认值
1 | const currentUser = { |
updating the cache
可以通过context访问或者更新 cache. Apollo cache API 有几个方法
writeData
直接在 Cahce 中写入数据,不用通过 query.
1 | const filter = { |
如果传递id属性,也可以在已经存在的对象中写入片段数据.
这里的id应该对应对象的 cache key. 如果使用InMemroyCache,并且没有覆盖dataObjectFromId,cache key就是_typename:id
1 | const user = { |
writeQuery 和 readQuery
在某些情况下,写入到 cache 的数据依赖于已经存在的数据,例如 ,在 list 中添加一条 item或者对属性做修改. 做法是使用cache.readQuery传递 query,在写入数据之前从 cache 中读取数据. 看看 list的例子
1 | let nextTodoId = 0; |
为了在 list 中添加 todo, 需要当前的 todos, 可以通过cache.readQuery获取.
为了写入数据到 cache.可以使用cache.writeQuery,cache.writeData. 不同点在于cache.writeQuery需要传递 query,来验证 data的结构. 在底层,cache.write自动从data构建了 query.
writeFragment 和 readFragment
cache.writeFragment,在有了 cache key 情况下, 可以灵活的读取数据.
1 | const todos = { |
@client directive
Combining local and remote data
下面的例子中,我们从 server 获取到 username,从 apollo cache 获取到 cart 信息.两者在结果中融合在一起
1 | const getUser = gql` |